package com.wuzhipeng.heart.user.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWTUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wuzhipeng.heart.user.config.UserContext;
import com.wuzhipeng.heart.user.convention.Constants.CacheConstants;
import com.wuzhipeng.heart.user.convention.TimeConstants.loginTimeOut;
import com.wuzhipeng.heart.user.convention.errorcode.BaseErrorCode;
import com.wuzhipeng.heart.user.convention.exception.ClientException;
import com.wuzhipeng.heart.user.convention.secret.loginSecret;
import com.wuzhipeng.heart.user.dao.entity.Users;
import com.wuzhipeng.heart.user.dao.mapper.UsersMapper;
import com.wuzhipeng.heart.user.dto.request.PasswordDTO;
import com.wuzhipeng.heart.user.dto.request.UsersDataDTO;
import com.wuzhipeng.heart.user.dto.request.registerDTO;
import com.wuzhipeng.heart.user.service.IUsersService;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.redisson.client.RedisClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author wuzhipeng
 * @since 2024-12-22
 */
@Service
@RequiredArgsConstructor
public class UsersServiceImpl extends ServiceImpl<UsersMapper, Users> implements IUsersService {
    private final loginTimeOut logintimeout;
    private final loginSecret loginsecret;
    private final RBloomFilter<String> userRegisterCachePenetrationBloomFilter;
    private final StringRedisTemplate stringRedisTemplate;
    private final RedissonClient redissonClient;

    @Override
    public String login(String phone, String password) {
            if (phone== null ||phone.isEmpty()) {
                throw new ClientException(BaseErrorCode.PHONE_VERIFY_ERROR);
            }
            if(password == null &&!password.isEmpty())
                throw new ClientException(BaseErrorCode.PASSWORD_VERIFY_ERROR);

        LambdaQueryWrapper<Users> wrapper = Wrappers.lambdaQuery(Users.class)
                .eq(Users::getPhone, phone)
                .eq(Users::getPassword, password);
        Users user = baseMapper.selectOne(wrapper);
        if(user == null)
            throw new ClientException(BaseErrorCode.USER_LOGIN_ERROR);
        Map<String, Object> map = new HashMap<>();
        map.put("phone", user.getPhone());
        map.put("expirationTime",logintimeout.getTime()+System.currentTimeMillis());
        return JWTUtil.createToken(map,loginsecret.getLoginsecret().getBytes());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateProfile(UsersDataDTO usersDataDTO) {

        Users users = BeanUtil.copyProperties(usersDataDTO, Users.class);
        if(usersDataDTO.getName()!=null && !usersDataDTO.getName().isEmpty())
            users.setUsername(usersDataDTO.getName());
        LambdaUpdateWrapper<Users> wrapper = Wrappers.lambdaUpdate(Users.class)
               .eq(Users::getPhone, UserContext.getPhone())
               .set(Users::getUsername, users.getUsername())
               .set(Users::getGender, users.getGender())
               .set(Users::getBirthday, users.getBirthday())
               .set(Users::getBio, users.getBio())
                .set(Users::getEmail, users.getEmail());
        int update = baseMapper.update(users, wrapper);
        if(update != 1)
            throw new ClientException(BaseErrorCode.USER_UPDATE_ERROR);
        //更新缓存
        stringRedisTemplate.delete(CacheConstants.USER_DATA_CACHE + UserContext.getPhone());
        stringRedisTemplate.opsForValue().set(CacheConstants.USER_DATA_CACHE + UserContext.getPhone(), JSONUtil.toJsonStr(usersDataDTO),60*60, TimeUnit.SECONDS);
    }

    @Override
    public UsersDataDTO getUserInfo(String token) {
        String phone = UserContext.getPhone();
        if(stringRedisTemplate.hasKey(CacheConstants.USER_DATA_CACHE + phone))
        {
            String jsonStr = stringRedisTemplate.opsForValue().get(CacheConstants.USER_DATA_CACHE + phone);
            return JSONUtil.toBean(jsonStr, UsersDataDTO.class);
        }
        LambdaQueryWrapper<Users> wrapper = Wrappers.lambdaQuery(Users.class)
                .eq(Users::getPhone, phone);
        Users user = baseMapper.selectOne(wrapper);

        if(user == null)
            throw new ClientException(BaseErrorCode.USER_NOT_EXIST_ERROR);
        UsersDataDTO usersDataDTO = BeanUtil.copyProperties(user, UsersDataDTO.class);
        usersDataDTO.setName(user.getUsername());
        if(usersDataDTO.getName() == null||usersDataDTO.getName().isEmpty())
            usersDataDTO.setName("请填写你的姓名");
        stringRedisTemplate.opsForValue().set(CacheConstants.USER_DATA_CACHE + phone, JSONUtil.toJsonStr(usersDataDTO),60*60, TimeUnit.SECONDS);
        return usersDataDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void registerClient(registerDTO registerDTO) {
        Users users = BeanUtil.copyProperties(registerDTO, Users.class);
        users.setUsername(registerDTO.getName());
        if(userRegisterCachePenetrationBloomFilter.contains(registerDTO.getPhone()))
        {
            LambdaQueryWrapper<Users> wrapper = Wrappers.lambdaQuery(Users.class);
            wrapper.eq(Users::getPhone, users.getPhone());
            Users user = baseMapper.selectOne(wrapper);
            if(user != null)
            {
                throw new ClientException(BaseErrorCode.USER_EXIST_ERROR);
            }
        }
        try {
            int insert = baseMapper.insert(users);
        } catch (Exception e) {

            userRegisterCachePenetrationBloomFilter.add(users.getPhone());
            throw new ClientException(BaseErrorCode.USER_REGISTER_ERROR);
        }
        userRegisterCachePenetrationBloomFilter.add(users.getPhone());
    }

    @Override
    public Users getUserByPhone(String therapistPhone) {
        LambdaQueryWrapper<Users> wrapper = Wrappers.lambdaQuery(Users.class)
                .eq(Users::getPhone, therapistPhone);
        return baseMapper.selectOne(wrapper);
    }

    @Override
    public void updatePassword(PasswordDTO passwordDTO) {
        String phone = UserContext.getPhone();
        LambdaUpdateWrapper<Users> wrapper = Wrappers.lambdaUpdate(Users.class)
               .eq(Users::getPhone, phone)
               .eq(Users::getPassword, passwordDTO.getOldPassword())
                .set(Users::getPassword, passwordDTO.getNewPassword());
        int update = baseMapper.update(null, wrapper);
        if(update != 1)
            throw new ClientException(BaseErrorCode.USER_UPDATE_ERROR);

    }
}
